package com.contory.ssn_lgnd.framework.math;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import com.contory.ssn_lgnd.app.maingame.ColiObjPtr;

import android.util.FloatMath;

public class SpatialHashGrid {
	public LinkedList<ColiObjPtr>[] dynamicCells;
	public LinkedList<ColiObjPtr>[] staticCells;
    int cellsPerRow;
    int cellsPerCol;
    float cellSize;
    int[] cellIds = new int[4];
    LinkedList<ColiObjPtr> foundObjects;
    
    @SuppressWarnings("unchecked")
    public SpatialHashGrid(float worldWidth, float worldHeight, float cellSize) {
        this.cellSize = cellSize;
        this.cellsPerRow = (int)FloatMath.ceil(worldWidth/cellSize);
        this.cellsPerCol = (int)FloatMath.ceil(worldHeight/cellSize);
        
        int numCells = cellsPerRow * cellsPerCol;
        dynamicCells = new LinkedList[numCells];
        staticCells = new LinkedList[numCells];
        for(int i = 0; i < numCells; i++) {
            dynamicCells[i] = new LinkedList<ColiObjPtr>();
            staticCells[i] = new LinkedList<ColiObjPtr>();
        }
        foundObjects = new LinkedList<ColiObjPtr>();
    }
    
    public void addStaticObject(ColiObjPtr obj) {
        int[] cellIds = getCellIds(obj);
        int i = 0;
        int cellId = -1;
        while((cellId = cellIds[i++]) != -1 && i < 4) {
            staticCells[cellId].add(obj);
        }
    }
    
    public void addDynamicObject(ColiObjPtr obj) {
        int[] cellIds = getCellIds(obj);
        int i = 0;
        int cellId = -1;
        while((cellId = cellIds[i++]) != -1 && i < 4) {
            dynamicCells[cellId].add(obj);
        }
    }
    
    public void removeObject(ColiObjPtr obj) {
        int[] cellIds = getCellIds(obj);
        int i = 0;
        int cellId = -1;
        while((cellId = cellIds[i++]) != -1) {
            dynamicCells[cellId].remove(obj);
            staticCells[cellId].remove(obj);
        }
    }
    
    public void clearDynamicCells() {
        int len = dynamicCells.length;
        for(int i = 0; i < len; i++) {
            dynamicCells[i].clear();
        }
    }
    
    public LinkedList<ColiObjPtr> getPotentialColliders(ColiObjPtr obj) {
        foundObjects.clear();
        int[] cellIds = getCellIds(obj);
        int i = 0;
        int cellId = -1;
        while((cellId = cellIds[i++]) != -1 && i < 4) {
            int len = dynamicCells[cellId].size();
            for(int j = 0; j < len; j++) {
            	ColiObjPtr collider = dynamicCells[cellId].get(j);
                if(!foundObjects.contains(collider))
                    foundObjects.add(collider);
            }
            
            len = staticCells[cellId].size();
            for(int j = 0; j < len; j++) {
            	ColiObjPtr collider = staticCells[cellId].get(j);
                if(!foundObjects.contains(collider))
                    foundObjects.add(collider);
            }
        }
        return foundObjects;
    }
    
    public int[] getCellIds(ColiObjPtr obj) {
        //int x1 = (int)FloatMath.floor(obj.getBoundingBox().lowerLeft.x / cellSize);
        //int y1 = (int)FloatMath.floor(obj.getBoundingBox().lowerLeft.y / cellSize);
        //int x2 = (int)FloatMath.floor((obj.getBoundingBox().lowerLeft.x
        //		+ obj.getBoundingBox().width) / cellSize);
        //int y2 = (int)FloatMath.floor((obj.getBoundingBox().lowerLeft.y
        //		+ obj.getBoundingBox().height) / cellSize);
        int x1 = -1, x2 = -1, y1 = -1, y2 = -1;
        if(x1 == x2 && y1 == y2) {
            if(x1 >= 0 && x1 < cellsPerRow && y1 >= 0 && y1 < cellsPerCol)
                cellIds[0] = x1 + y1 * cellsPerRow;
            else
                cellIds[0] = -1;
            cellIds[1] = -1;
            cellIds[2] = -1;
            cellIds[3] = -1;
        }
        else if(x1 == x2) {
            int i = 0;
            if(x1 >= 0 && x1 < cellsPerRow) {
                if(y1 >= 0 && y1 < cellsPerCol)
                    cellIds[i++] = x1 + y1 * cellsPerRow;
                if(y2 >= 0 && y2 < cellsPerCol)
                    cellIds[i++] = x1 + y2 * cellsPerRow;
            }
            while(i <= 3) cellIds[i++] = -1;
        }
        else if(y1 == y2) {
            int i = 0;
            if(y1 >= 0 && y1 < cellsPerCol) {
                if(x1 >= 0 && x1 < cellsPerRow)
                    cellIds[i++] = x1 + y1 * cellsPerRow;
                if(x2 >= 0 && x2 < cellsPerRow)
                    cellIds[i++] = x2 + y1 * cellsPerRow;
            }
            while(i <= 3) cellIds[i++] = -1;                       
        }
        else {
            int i = 0;
            int y1CellsPerRow = y1 * cellsPerRow;
            int y2CellsPerRow = y2 * cellsPerRow;
            if(x1 >= 0 && x1 < cellsPerRow && y1 >= 0 && y1 < cellsPerCol)
                cellIds[i++] = x1 + y1CellsPerRow;
            if(x2 >= 0 && x2 < cellsPerRow && y1 >= 0 && y1 < cellsPerCol)
                cellIds[i++] = x2 + y1CellsPerRow;
            if(x2 >= 0 && x2 < cellsPerRow && y2 >= 0 && y2 < cellsPerCol)
                cellIds[i++] = x2 + y2CellsPerRow;
            if(x1 >= 0 && x1 < cellsPerRow && y2 >= 0 && y2 < cellsPerCol)
                cellIds[i++] = x1 + y2CellsPerRow;
            while(i <= 3) cellIds[i++] = -1;
        }
        return cellIds;
    }
}
